package com.powerteam.service.sys.impl;

import com.alibaba.fastjson.JSON;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.powerteam.exception.BusinessException;
import com.powerteam.mapper.sys.UserMapper;
import com.powerteam.model.sys.User;
import com.powerteam.service.sys.UserService;
import com.powerteam.util.DateUtil;
import com.powerteam.vo.Result;
import com.powerteam.vo.ResultData;
import com.powerteam.vo.sys.QueryUserVO;
import com.powerteam.vo.sys.UpdatePasswordVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.DigestUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import static com.powerteam.model.enums.UserStatusEnum.USER_STATUS_ON;

/**
 * 用户相关服务接口实现
 *
 * @author jinming.zhang
 * @version 0.0.1
 * @date 2021/12/30
 */
@Slf4j
@Service
public class UserServiceImpl implements UserService {

    private static final String CLASS_NAME = "UserServiceImpl";

    @Autowired
    private UserMapper userMapper;

    /**
     * 定时任务 每天凌晨0时0分0秒去重置一次登录次数
     *
     * @param
     * @return void
     * @Author jinming.zhang
     * @Date 2022/5/11
     */
    @Scheduled(cron = "0 0 0 * * ?")
    public void updatePswErrorNumber() {

        int i = -1;
        int resetNumber = 0;
        while (true) {
            if (i >= 0) {
                return;
            }
            try {
                i = userMapper.resetPswErrorNumber();
                log.info("{} updatePswErrorNumber 重置登录次数 时间：{} 重置数量：{}", CLASS_NAME,
                        new SimpleDateFormat("yyyy年MM月dd日 HH时mm分ss秒").format(new Date()), i);
            } catch (Exception e) {
                i = -1;
                log.error(e.getMessage(), e);
                log.info("{} updatePswErrorNumber 重置登录次数失败 尝试重新重置 {}, 重试中!", CLASS_NAME, ++resetNumber);
                if (resetNumber >= 10) {
                    log.info("{} updatePswErrorNumber 重置失败达到 {} 次, 请联系开发人员处理!", CLASS_NAME, resetNumber);
                    return;
                }
            }
        }
    }

    @Override
    @Transactional(rollbackFor = {BusinessException.class}, propagation = Propagation.REQUIRED)
    public ResultData<User> signIn(User user) {

        log.info("{} signIn 用户登录接口 入参0:{}", CLASS_NAME, JSON.toJSON(user));
        ResultData<User> result = new ResultData<>();

        // 判断用户输入的的信息是否合法
        if (StringUtils.isEmpty(user.getUserName()) && StringUtils.isEmpty(user.getPassword())) {
            result.setMessage("用户名与密码不能为空!");
            return result;
        } else if (StringUtils.isEmpty(user.getUserName())) {
            result.setMessage("用户名不能为空!");
            return result;
        } else if (StringUtils.isEmpty(user.getPassword())) {
            result.setMessage("密码不能为空!");
            return result;
        }

        try {

            // 查询用户信息
            User resultUser = userMapper.signIn(user);
            log.info("{} signIn 查询用户信息 入参0:{} 结果0:{}", CLASS_NAME, JSON.toJSON(user), JSON.toJSON(resultUser));

            // 对结果进行判断
            if (!ObjectUtils.isEmpty(resultUser)) {

                // 判断当日密码输入错误次数
                if (resultUser.getPswErrorNumber() >= 10) {
                    result.setMessage("当日密码连续输入错误已达10次，请联系管理员重置密码或次日重试!");
                    return result;
                }

                // 将查询结果与用户信息相比较
                if (DigestUtils.md5DigestAsHex(user.getPassword().getBytes()).equals(resultUser.getPassword())
                        && user.getUserName().equals(resultUser.getUserName())) {

                    // 当密码输入正确 判断其当日连续错误次数，如果未达到10次，则重置一下当日次数
                    if (resultUser.getPswErrorNumber() > 0 && resultUser.getPswErrorNumber() < 10) {
                        userMapper.pswErrorNumber(User.builder().userId(resultUser.getUserId())
                                .pswErrorNumber(0).build());
                    }

                    // 如果用户名跟密码相等, 判断用户状态
                    if (USER_STATUS_ON.getCode().equals(resultUser.getStatus())) {
                        result.setSuccess(true);
                        // 将密码设置为空
                        resultUser.setPassword(null);
                        result.setData(resultUser);
                    } else {
                        result.setMessage("当前用户已禁用, 请联系管理员!");
                    }
                } else {

                    // 如果用户输入密码错误 添加一次错误次数
                    int i = resultUser.getPswErrorNumber() + 1;
                    userMapper.pswErrorNumber(User.builder().userId(resultUser.getUserId())
                            .pswErrorNumber(i).build());
                    result.setMessage("密码连续错误" + i + "次,本日连续输入错误达到10次将禁止登录!");
                }
            } else {
                result.setMessage("用户不存在!");
            }
            return result;

        } catch (Exception e) {
            log.warn("{} signIn 查询用户信息异常 入参0:{}", CLASS_NAME, JSON.toJSON(user));
            log.error(e.getMessage(), e);
            throw new BusinessException("系统异常, 请稍后重试!");
        }

    }

    @Override
    public Result checkUserName(User user) {

        try {

            Boolean existUserName = userMapper.existUserName(user);
            log.info("{} checkUserName 检查用户名是否重复 入参0:{} 结果0:{}", CLASS_NAME, JSON.toJSON(user), existUserName);

            return new Result(!existUserName);
        } catch (Exception e) {
            log.warn("{} checkUserName 检查用户名是否重复异常 入参0:{}", CLASS_NAME, JSON.toJSON(user));
            log.error(e.getMessage(), e);
            return new Result();
        }
    }

    @Override
    @Transactional(rollbackFor = {BusinessException.class}, propagation = Propagation.REQUIRED)
    public Result insert(User user) {

        try {

            if (!checkUserName(user).isSuccess()) {
                return new Result(false, "用户名重复");
            }

            // 新增用户
            user.setCreateAt(new Date());
            user.setStatus(USER_STATUS_ON.getCode());

            // 对用户密码进行加密
            user.setPassword(DigestUtils.md5DigestAsHex(user.getPassword().getBytes()));
            boolean result = userMapper.insert(user) > 0;
            log.info("{} insert 添加用户 入参0:{} 结果0:{}", CLASS_NAME, JSON.toJSON(user), result);

            return new Result(result);
        } catch (Exception e) {
            log.warn("{} insert 添加用户异常 入参0:{}", CLASS_NAME, JSON.toJSON(user));
            log.error(e.getMessage(), e);
            throw new BusinessException("添加用户失败");
        }
    }

    @Override
    public PageInfo<User> find(QueryUserVO vo) {

        try {

            // 处理参数
            vo.setStartDate(DateUtil.toStartDate(vo.getStartDate()));
            vo.setEndDate(DateUtil.toEndDate(vo.getEndDate()));
            vo.setWord(StringUtils.isEmpty(vo.getWord()) ? null : "%".concat(vo.getWord()).concat("%"));
            if (StringUtils.isEmpty(vo.getDisablePaging()) || !vo.getDisablePaging()) {
                PageHelper.startPage(vo.getPageNum(), vo.getPageSize());
            }
            List<User> userList = userMapper.find(vo);
            log.info("{} find 查询用户 入参 0:{} 结果0:{}", CLASS_NAME, JSON.toJSON(vo), JSON.toJSON(userList));

            return new PageInfo<>(userList);
        } catch (Exception e) {
            log.warn("{} find 查询用户异常 入参0:{}", CLASS_NAME, JSON.toJSON(vo));
            log.error(e.getMessage(), e);
            return new PageInfo<>(new ArrayList<>());
        }
    }

    @Override
    @Transactional(rollbackFor = {BusinessException.class}, propagation = Propagation.REQUIRED)
    public Result deleteByIds(List<Integer> ids) {

        try {

            boolean result = userMapper.deleteByIds(ids) > 0;
            log.info("{} deleteByIds 批量删除用户 入参 0:{} 结果0:{}", CLASS_NAME, JSON.toJSON(ids), result);

            return new Result(result);
        } catch (Exception e) {
            log.info("{} deleteByIds 批量删除用户异常 入参 0:{}", CLASS_NAME, JSON.toJSON(ids));
            log.error(e.getMessage(), e);
            throw new BusinessException("删除用户失败");
        }

    }

    @Override
    public User findById(Integer userId) {

        try {

            // 根据用户Id获取用户信息
            User user = userMapper.findById(userId);
            log.info("{} findById 根据用户Id获取用户信息 入参0:{} 结果0:{}", CLASS_NAME, userId, JSON.toJSON(user));

            return user;
        } catch (Exception e) {
            log.warn("{} findById 根据用户Id获取用户信息异常 入参0:{}", CLASS_NAME, userId);
            log.error(e.getMessage(), e);
            return new User();
        }

    }

    @Override
    @Transactional(rollbackFor = {BusinessException.class}, propagation = Propagation.REQUIRED)
    public User update(User user) {

        try {

            // 更新用户
            boolean result = userMapper.update(user) > 0;
            // 返回更新信息
            User updateUser = userMapper.findById(user.getUserId());
            log.info("{} update 更新用户 入参0:{} 更新后0:{}", CLASS_NAME, JSON.toJSON(user), JSON.toJSON(updateUser));
            if (result && !ObjectUtils.isEmpty(updateUser)) {
                return updateUser;
            } else {
                throw new BusinessException("更新用户信息失败");
            }
        } catch (BusinessException e) {
            log.warn("{} update 更新用户异常 入参0:{}", CLASS_NAME, JSON.toJSON(user));
            log.error(e.getMessage(), e);
            throw new BusinessException("更新用户信息失败");
        }

    }

    @Override
    @Transactional(rollbackFor = {BusinessException.class}, propagation = Propagation.REQUIRED)
    public Result updateStatus(User user) {

        try {

            User model = userMapper.findById(user.getUserId());
            model.setStatus(user.getStatus());
            // 更新用户状态 (启用/禁用)
            boolean result = userMapper.update(model) > 0;
            log.info("{} updateStatus 更新用户状态(启用/禁用) 入参0:{} 结果0:{}", CLASS_NAME, JSON.toJSON(model), result);

            return new Result(result);
        } catch (Exception e) {
            log.warn("{} updateStatus 更新用户状态(启用/禁用)异常 入参0:{}", CLASS_NAME, JSON.toJSON(user));
            log.error(e.getMessage(), e);
            throw new BusinessException("更新用户状态失败");
        }

    }

    @Override
    @Transactional(rollbackFor = {BusinessException.class}, propagation = Propagation.REQUIRED)
    public Result resetPassword(User user) {

        try {

            // 对密码进行加密处理
            user.setPassword(DigestUtils.md5DigestAsHex("123456".getBytes()));
            // 将错误次数重置为0
            user.setPswErrorNumber(0);
            boolean result = userMapper.resetPassword(user) > 0;
            log.info("{} resetPassword 重置密码 入参0:{} 结果0:{}", CLASS_NAME, JSON.toJSON(user), result);

            return new Result(result);
        } catch (Exception e) {
            log.warn("{} resetPassword 重置密码异常 入参0:{}", CLASS_NAME, JSON.toJSON(user));
            log.error(e.getMessage(), e);
            throw new BusinessException("重置密码失败");
        }

    }

    @Override
    @Transactional(rollbackFor = {BusinessException.class}, propagation = Propagation.REQUIRED)
    public Result updatePassword(UpdatePasswordVO user) {

        try {

            User rawUser = userMapper.findById(user.getUserId());
            if (!ObjectUtils.isEmpty(rawUser) && rawUser.getPassword().equals(DigestUtils.md5DigestAsHex(user.getRawPassword().getBytes()))) {

                // 修改密码 将新密码加密存入数据库
                user.setPassword(DigestUtils.md5DigestAsHex(user.getPassword().getBytes()));
                boolean result = userMapper.resetPassword(user) > 0;
                log.info("{} updatePassword 修改密码 入参0:{} 结果0:{}", CLASS_NAME, JSON.toJSON(user), result);

                return new Result(result);
            } else {
                return new Result(false, "原密码不正确");
            }
        } catch (Exception e) {
            log.warn("{} updatePassword 修改密码异常 入参0:{}", CLASS_NAME, JSON.toJSON(user));
            log.error(e.getMessage(), e);
            throw new BusinessException("修改密码失败");
        }

    }
}
